#ifndef _CANARY2_SYS_TASK_MANAGER_H_
#define _CANARY2_SYS_TASK_MANAGER_H_

#include <memory>
#include <concepts>

#include "resumable.h"

#include "../sys/scheduler_concepts.h"
#include "../sys/TMR_concepts.h"
#include "../util/concepts.h"
#include "../util/concurrentqueue.h"

namespace wilson::sys
{
    class task_mgr_empty_waker
    {
    public:
        constexpr void awake() const noexcept {}
        constexpr void operator()() const noexcept {}
    };

    class normal_task_mgr 
        : public ::std::enable_shared_from_this<normal_task_mgr>
    {
    public:
        normal_task_mgr() = default;
        static ::std::shared_ptr<normal_task_mgr> 
            make_task_mgr();
        static ::std::shared_ptr<normal_task_mgr> 
            get_from_global();
        void registe_globally();

        resumable get_task();
        void enqueue_task(resumable r);
        resumable get_task(moodycamel::ConsumerToken&);
        void enqueue_task(moodycamel::ProducerToken& t, resumable r);

        bool empty() const noexcept 
            { return ntm_queue.size_approx() == 0; }

        constexpr void stop() const noexcept {}

        auto get_moodycamel_consumer_tk()
        {
            return moodycamel::ConsumerToken(ntm_queue);
        }

    private:
        moodycamel::ConcurrentQueue<resumable> ntm_queue;
    };

    template<typename TaskM>
    concept task_manager = 
        ::std::default_initializable<TaskM> && 
        ::std::move_constructible<TaskM> && 
    requires(TaskM t)
    {
        t.enqueue_task(::std::declval<resumable>());
        { t.empty() } -> ::std::same_as<bool>;
        { t.get_task() } -> ::std::same_as<resumable>;
        t.stop();
        t.registe_globally();
        { TaskM::get_from_global() } -> ::std::convertible_to<::std::shared_ptr<TaskM>>;
    };

    template<task_manager TM>
    class task_manager_registration
    {
    public:
        using task_manager_type = TM;

    public:
        constexpr task_manager_registration() noexcept = default;
        ::std::shared_ptr<TM> next()
        {
            size_t new_iter{};
            if (tmr_regs.empty()) [[unlikely]] 
                return nullptr;
            else new_iter = (tmr_iteration + 1) % tmr_regs.size();
            auto ret = tmr_regs[tmr_iteration];
            tmr_iteration = new_iter;
            return ret;
        }

        void registe(::std::shared_ptr<TM> tm)
        {
            tmr_regs.emplace_back(tm);
        }

    private:
        ::std::vector<::std::shared_ptr<TM>> tmr_regs;
        size_t tmr_iteration{};
    };

    template<task_manager TM>
    decltype(auto) get_global_TMR()
    {
        static task_manager_registration<TM> ret;
        return (ret);
    }

    template<task_manager TaskM, typename Ivkb>
    void schedule(TaskM& schr, Ivkb&& r)
    {
        schr.enqueue_task(resumable{ ::std::forward<Ivkb>(r) });
    }
}

#endif
